{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Improving Predictions with `scikit-learn`\n",
    "\n",
    "In this chapter we will try the same regression as chapter 8, but this time without departure delay; a harder problem."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Imports loaded...\n"
     ]
    }
   ],
   "source": [
    "import sys, os, re\n",
    "sys.path.append(\"lib\")\n",
    "import utils\n",
    "\n",
    "import numpy as np\n",
    "import sklearn\n",
    "import iso8601\n",
    "import datetime\n",
    "print(\"Imports loaded...\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Original JSON file size: 45,056 Bytes\n",
      "Training items: 457,013\n",
      "Data loaded...\n"
     ]
    }
   ],
   "source": [
    "# Load and check the size of our training data. May take a minute.\n",
    "print(\"Original JSON file size: {:,} Bytes\".format(os.path.getsize(\"../data/simple_flight_delay_features.jsonl\")))\n",
    "training_data = utils.read_json_lines_file('../data/simple_flight_delay_features.jsonl')\n",
    "print(\"Training items: {:,}\".format(len(training_data))) # 457,013\n",
    "print(\"Data loaded...\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Size of training data in RAM: 4,018,008 Bytes\n",
      "{'ArrDelay': 4.0, 'CRSArrTime': '2015-01-19T14:54:00.000Z', 'CRSDepTime': '2015-01-19T12:40:00.000Z', 'Carrier': 'US', 'DayOfMonth': 19, 'DayOfWeek': 1, 'DayOfYear': 19, 'DepDelay': -1.0, 'Dest': 'PHX', 'Distance': 338.0, 'FlightDate': '2015-01-19T00:00:00.000Z', 'FlightNum': '1712', 'Origin': 'SNA'}\n"
     ]
    }
   ],
   "source": [
    "# Inspect a record before we alter them\n",
    "print(\"Size of training data in RAM: {:,} Bytes\".format(sys.getsizeof(training_data))) # 4MB\n",
    "print(training_data[0])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "# # We need to sample our data to fit into RAM\n",
    "# training_data = np.random.choice(training_data, 1000000) # 'Sample down to 1MM examples'\n",
    "# print(\"Sampled items: {:,} Bytes\".format(len(training_data)))\n",
    "# print(\"Data sampled...\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Results vectorized size: 3,656,200\n",
      "Results vectorized...\n"
     ]
    }
   ],
   "source": [
    "# Separate our results from the rest of the data, vectorize and size up\n",
    "results = [record['ArrDelay'] for record in training_data]\n",
    "results_vector = np.array(results)\n",
    "print(\"Results vectorized size: {:,}\".format(sys.getsizeof(results_vector))) # 3,656,200 bytes\n",
    "print(\"Results vectorized...\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "ArrDelay, DepDelay and FlightDate removed from training data...\n"
     ]
    }
   ],
   "source": [
    "# Remove the two delay fields and the flight date from our training data\n",
    "for item in training_data:\n",
    "  item.pop('ArrDelay', None)\n",
    "  item.pop('FlightDate', None)\n",
    "  item.pop('DepDelay', None)\n",
    "print(\"ArrDelay, DepDelay and FlightDate removed from training data...\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CRSArr/DepTime converted to unix time...\n"
     ]
    }
   ],
   "source": [
    "# Must convert datetime strings to unix times\n",
    "for item in training_data:\n",
    "  if isinstance(item['CRSArrTime'], str):\n",
    "    dt = iso8601.parse_date(item['CRSArrTime'])\n",
    "    unix_time = int(dt.timestamp())\n",
    "    item['CRSArrTime'] = unix_time\n",
    "  if isinstance(item['CRSDepTime'], str):\n",
    "    dt = iso8601.parse_date(item['CRSDepTime'])\n",
    "    unix_time = int(dt.timestamp())\n",
    "    item['CRSDepTime'] = unix_time\n",
    "print(\"CRSArr/DepTime converted to unix time...\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Sampled dimensions: [457,013]\n",
      "Size of DictVectorized vectors: 36,561,040 Bytes\n",
      "  (0, 0)\t1421679240.0\n",
      "  (0, 1)\t1421671200.0\n",
      "  (0, 13)\t1.0\n",
      "  (0, 16)\t19.0\n",
      "  (0, 17)\t1.0\n",
      "  (0, 18)\t19.0\n",
      "  (0, 249)\t1.0\n",
      "  (0, 331)\t338.0\n",
      "  (0, 1122)\t1.0\n",
      "  (0, 6946)\t1.0\n",
      "  (1, 0)\t1421669640.0\n",
      "  (1, 1)\t1421661600.0\n",
      "  (1, 13)\t1.0\n",
      "  (1, 16)\t19.0\n",
      "  (1, 17)\t1.0\n",
      "  (1, 18)\t19.0\n",
      "  (1, 249)\t1.0\n",
      "  (1, 331)\t338.0\n",
      "  (1, 4727)\t1.0\n",
      "  (1, 6946)\t1.0\n",
      "  (2, 0)\t1421703900.0\n",
      "  (2, 1)\t1421695800.0\n",
      "  (2, 13)\t1.0\n",
      "  (2, 16)\t19.0\n",
      "  (2, 17)\t1.0\n",
      "  :\t:\n",
      "  (457010, 18)\t11.0\n",
      "  (457010, 287)\t1.0\n",
      "  (457010, 331)\t987.0\n",
      "  (457010, 5237)\t1.0\n",
      "  (457010, 6907)\t1.0\n",
      "  (457011, 0)\t1420965000.0\n",
      "  (457011, 1)\t1420959600.0\n",
      "  (457011, 3)\t1.0\n",
      "  (457011, 16)\t11.0\n",
      "  (457011, 17)\t7.0\n",
      "  (457011, 18)\t11.0\n",
      "  (457011, 288)\t1.0\n",
      "  (457011, 331)\t421.0\n",
      "  (457011, 2657)\t1.0\n",
      "  (457011, 6907)\t1.0\n",
      "  (457012, 0)\t1421002200.0\n",
      "  (457012, 1)\t1420996800.0\n",
      "  (457012, 3)\t1.0\n",
      "  (457012, 16)\t11.0\n",
      "  (457012, 17)\t7.0\n",
      "  (457012, 18)\t11.0\n",
      "  (457012, 288)\t1.0\n",
      "  (457012, 331)\t421.0\n",
      "  (457012, 2983)\t1.0\n",
      "  (457012, 6907)\t1.0\n",
      "Training data vectorized...\n"
     ]
    }
   ],
   "source": [
    "# Use DictVectorizer to convert feature dicts to vectors\n",
    "from sklearn.feature_extraction import DictVectorizer\n",
    "\n",
    "print(\"Sampled dimensions: [{:,}]\".format(len(training_data)))\n",
    "vectorizer = DictVectorizer()\n",
    "training_vectors = vectorizer.fit_transform(training_data)\n",
    "print(\"Size of DictVectorized vectors: {:,} Bytes\".format(training_vectors.data.nbytes))\n",
    "print(training_vectors)\n",
    "print(\"Training data vectorized...\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(411311, 6978) (45702, 6978)\n",
      "(411311,) (45702,)\n",
      "Test train split performed again...\n"
     ]
    }
   ],
   "source": [
    "from sklearn.model_selection import train_test_split\n",
    "# Redo test/train split\n",
    "X_train, X_test, y_train, y_test = train_test_split(\n",
    "  training_vectors,\n",
    "  results_vector,\n",
    "  test_size=0.1,\n",
    "  random_state=17\n",
    ")\n",
    "print(X_train.shape, X_test.shape)\n",
    "print(y_train.shape, y_test.shape)\n",
    "print(\"Test train split performed again...\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Gradient boosting regressor instantiated...!\n"
     ]
    }
   ],
   "source": [
    "from sklearn.ensemble import GradientBoostingRegressor\n",
    "\n",
    "regressor = GradientBoostingRegressor()\n",
    "print(\"Gradient boosting regressor instantiated...!\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Regressor fitted again...\n"
     ]
    }
   ],
   "source": [
    "# Refit regression on new training data\n",
    "regressor.fit(X_train, y_train)\n",
    "print(\"Regressor fitted again...\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Predictions made for X_test again...\n"
     ]
    }
   ],
   "source": [
    "# Predict using the test data again\n",
    "predicted = regressor.predict(X_test.toarray())\n",
    "print(\"Predictions made for X_test again...\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Median absolute error:    13.6\n",
      "r2 score:                 0.116\n"
     ]
    }
   ],
   "source": [
    "from sklearn.metrics import median_absolute_error, r2_score\n",
    "\n",
    "# Get the median absolute error again\n",
    "medae = median_absolute_error(y_test, predicted)\n",
    "print(\"Median absolute error:    {:.3g}\".format(medae))\n",
    "\n",
    "# Get the r2 score gain\n",
    "r2 = r2_score(y_test, predicted)\n",
    "print(\"r2 score:                 {:.3g}\".format(r2))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# Plot outputs, compare actual vs predicted values\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "plt.scatter(\n",
    "  y_test,\n",
    "  predicted,\n",
    "  color='blue',\n",
    "  linewidth=1\n",
    ")\n",
    "\n",
    "plt.xticks(())\n",
    "plt.yticks(())\n",
    "\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAiwAAAGdCAYAAAAxCSikAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAPYQAAD2EBqD+naQAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4xLjEsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy8QZhcZAAAgAElEQVR4nO3de3wU9b3/8fcSliXBJCWEJIREpC310kCr0EJQBESCCKgHb4CmePSH9SggRYqibQk+imBVxOqRtpZqFShUibdq0wQrKIeLCqZysRYtyi0BVEiAYLKG+f0x3SWb7G02m91J8no+HnnI7s7OznzcZN/7ne/FYRiGIQAAABvrEO8DAAAACIXAAgAAbI/AAgAAbI/AAgAAbI/AAgAAbI/AAgAAbI/AAgAAbI/AAgAAbK9jvA8gEqdOndKBAweUnJwsh8MR78MBAABhMAxDx44dU3Z2tjp0sNZm0ioDy4EDB5SbmxvvwwAAABHYu3evcnJyLD2nVQaW5ORkSeYJp6SkxPlorHG73SotLVVBQYGcTme8D8eWqFFw1Cc0ahQaNQqO+oQWSY2qq6uVm5vr/Ry3olUGFs9loJSUlFYZWJKSkpSSksIvQQDUKDjqExo1Co0aBUd9QmtOjSLpzkGnWwAAYHsEFgAAYHsEFgAAYHsEFgAAYHsEFgAAYHsEFgAAYHsEFgAAYHsEFgAAYHutcuI4AM1XXy+9/bZUUSH16CENGSIlJMT7qADAPwIL0A4VF0t33int23f6vpwc6bHHpPHj43dcABAIl4SAdqa4WLrmGt+wIkn795v3FxfH57gAIBgCC9CO1NebLSuG0fQxz30zZpjbAYCdWAosS5YsUb9+/byLDubn5+uvf/2r9/Fhw4bJ4XD4/EyYMMFnH0eOHFFhYaFSU1OVmpqqwsJCHT16NDpnAyCot99u2rLSkGFIe/ea2wGAnVgKLDk5OVq4cKHee+89vffee7rkkkt05ZVXaseOHd5tpkyZooqKCu/Pb3/7W599TJo0SeXl5SopKVFJSYnKy8tVWFgYnbMBEFRFRXS3A4BYsdTpdty4cT6358+fryVLlmjTpk367ne/K0lKSkpSVlaW3+d/+OGHKikp0aZNmzRw4EBJ0lNPPaX8/Hx99NFHOvvssyM5BwBh6tEjutsBQKxEPEqovr5ezz//vE6cOKH8/Hzv/cuXL9eyZcuUmZmp0aNHa+7cuUpOTpYkbdy4Uampqd6wIkmDBg1SamqqNmzYEDCw1NbWqra21nu7urpakuR2u+V2uyM9hbjwHG9rO+5YokbBNac+gwZJ3/62dOCA/34sDofUs6e5XWsuP++h0KhRcNQntEhq1Jx6OgzD35+twLZt26b8/Hx99dVXOuOMM7RixQpdfvnlkszWkt69eysrK0vbt2/XnDlz9O1vf1tlZWWSpAceeEDPPPOM/vWvf/ns8zvf+Y7++7//W3PmzPH7mkVFRZo3b16T+1esWKGkpCQrhw8AAOKkpqZGkyZNUlVVlVJSUiw913ILy9lnn63y8nIdPXpUq1ev1uTJk7Vu3Tqdd955mjJline7vLw89enTRwMGDNDWrVt1wQUXSJIcDkeTfRqG4fd+jzlz5mjmzJne29XV1crNzVVBQYHlE443t9utsrIyjRw5Uk6nM96HY0vUKLho1OfVV6W77zaHMnvk5EgLF0qNrvy2SryHQqNGwVGf0CKpkecKSSQsB5ZOnTrp29/+tiRpwIABevfdd/XYY4816VwrSRdccIGcTqd27dqlCy64QFlZWTp48GCT7Q4fPqzMzMyAr+lyueRyuZrc73Q6W+0bqTUfe6xQo+CaU5/x46Urr2z7M93yHgqNGgVHfUKzUqPm1LLZM90ahuHTv6ShHTt2yO12q8d/evDl5+erqqpK77zzjn74wx9KkjZv3qyqqioNHjy4uYcCwIKEBGnYsHgfBQCEx1JguffeezV69Gjl5ubq2LFjWrlypdauXauSkhJ98sknWr58uS6//HKlp6dr586duuuuu3T++efrwgsvlCSde+65uuyyyzRlyhRvi8ytt96qsWPHMkIIAAAEZCmwHDx4UIWFhaqoqFBqaqr69eunkpISjRw5Unv37tUbb7yhxx57TMePH1dubq7GjBmjuXPnKqFBO/Py5cs1ffp0FRQUSJKuuOIKPfHEE9E9KwAA0KZYCixLly4N+Fhubq7WrVsXch9paWlatmyZlZcFAADtHGsJAQAA2yOwAAAA2yOwAAAA2yOwAAAA2yOwAAAA2yOwAAAA2yOwAAAA2yOwAAAA2yOwAAAA2yOwAAAA2yOwAAAA2yOwAAAA2yOwAAAA2yOwAAAA2yOwAAAA2yOwAAAA2yOwAAAA2yOwAAAA2yOwAAAA2yOwAAAA2yOwAAAA2yOwAAAA2yOwAAAA2yOwAAAA2yOwAAAA2yOwAAAA2yOwAAAA2yOwAAAA2yOwAAAA2yOwAAAA2yOwAAAA2yOwAAAA2yOwAAAA2yOwAAAA2yOwAAAA27MUWJYsWaJ+/fopJSVFKSkpys/P11//+lfv47W1tZo2bZrS09PVpUsXXXHFFdq3b5/PPvbs2aNx48apS5cuSk9P1/Tp01VXVxedswEAAG2SpcCSk5OjhQsX6r333tN7772nSy65RFdeeaV27NghSZoxY4ZefPFFrVy5UuvXr9fx48c1duxY1dfXS5Lq6+s1ZswYnThxQuvXr9fKlSu1evVq3XXXXdE/MwAA0GZ0tLLxuHHjfG7Pnz9fS5Ys0aZNm5STk6OlS5fqueee06WXXipJWrZsmXJzc7VmzRqNGjVKpaWl2rlzp/bu3avs7GxJ0iOPPKKbbrpJ8+fPV0pKSpROCwAAtCWWAktD9fX1ev7553XixAnl5+dry5YtcrvdKigo8G6TnZ2tvLw8bdiwQaNGjdLGjRuVl5fnDSuSNGrUKNXW1mrLli0aPny439eqra1VbW2t93Z1dbUkye12y+12R3oKceE53tZ23LFEjYKjPqFRo9CoUXDUJ7RIatSceloOLNu2bVN+fr6++uornXHGGXrxxRd13nnnqby8XJ06dVLXrl19ts/MzFRlZaUkqbKyUpmZmT6Pd+3aVZ06dfJu48+CBQs0b968JveXlpYqKSnJ6inYQllZWbwPwfaoUXDUJzRqFBo1Co76hGalRjU1NRG/juXAcvbZZ6u8vFxHjx7V6tWrNXnyZK1bty7g9oZhyOFweG83/HegbRqbM2eOZs6c6b1dXV2t3NxcFRQUtLrLSG63W2VlZRo5cqScTme8D8eWqFFw1Cc0ahQaNQqO+oQWSY08V0giYTmwdOrUSd/+9rclSQMGDNC7776rxx57TNdff73q6up05MgRn1aWQ4cOafDgwZKkrKwsbd682Wd/R44ckdvtbtLy0pDL5ZLL5Wpyv9PpbLVvpNZ87LFCjYKjPqFRo9CoUXDUJzQrNWpOLZs9D4thGKqtrVX//v3ldDp9moYqKiq0fft2b2DJz8/X9u3bVVFR4d2mtLRULpdL/fv3b+6hAACANspSC8u9996r0aNHKzc3V8eOHdPKlSu1du1alZSUKDU1VbfccovuuusudevWTWlpaZo1a5b69u3rHTVUUFCg8847T4WFhXrooYf05ZdfatasWZoyZUqru7QDAABix1JgOXjwoAoLC1VRUaHU1FT169dPJSUlGjlypCTp0UcfVceOHXXdddfp5MmTGjFihJ555hklJCRIkhISEvTaa6/p9ttv14UXXqjExERNmjRJDz/8cPTPDAAAtBmWAsvSpUuDPt65c2c9/vjjevzxxwNuc+aZZ+ovf/mLlZcFAADtHGsJAQAA2yOwAAAA2yOwAAAA2yOwAAAA2yOwAAAA2yOwAAAA2yOwAAAA2yOwAAAA2yOwAAAA2yOwAAAA2yOwAAAA2yOwAAAA2yOwAAAA2yOwAAAA2yOwAAAA2yOwAAAA2yOwAAAA2yOwAAAA2yOwAAAA2yOwAAAA2yOwAAAA2yOwAAAA2yOwAAAA2yOwAAAA2yOwAAAA2yOwAAAA2yOwAAAA2yOwAAAA2yOwAAAA2yOwAAAA2yOwAAAA2yOwAAAA2yOwAAAA2yOwAAAA2yOwAAAA27MUWBYsWKAf/OAHSk5OVkZGhq666ip99NFHPtsMGzZMDofD52fChAk+2xw5ckSFhYVKTU1VamqqCgsLdfTo0eafDQAAaJMsBZZ169bpjjvu0KZNm1RWVqavv/5aBQUFOnHihM92U6ZMUUVFhffnt7/9rc/jkyZNUnl5uUpKSlRSUqLy8nIVFhY2/2wAAECb1NHKxiUlJT63n376aWVkZGjLli26+OKLvfcnJSUpKyvL7z4+/PBDlZSUaNOmTRo4cKAk6amnnlJ+fr4++ugjnX322VbPAQAAtHGWAktjVVVVkqS0tDSf+5cvX65ly5YpMzNTo0eP1ty5c5WcnCxJ2rhxo1JTU71hRZIGDRqk1NRUbdiwwW9gqa2tVW1trfd2dXW1JMntdsvtdjfnFGLOc7yt7bhjiRoFR31Co0ahUaPgqE9okdSoOfWMOLAYhqGZM2fqoosuUl5envf+G264Qb1791ZWVpa2b9+uOXPm6B//+IfKysokSZWVlcrIyGiyv4yMDFVWVvp9rQULFmjevHlN7i8tLVVSUlKkpxBXnnogMGoUHPUJjRqFRo2Coz6hWalRTU1NxK8TcWCZOnWqPvjgA61fv97n/ilTpnj/nZeXpz59+mjAgAHaunWrLrjgAkmSw+Fosj/DMPzeL0lz5szRzJkzvberq6uVm5urgoICpaSkRHoKceF2u1VWVqaRI0fK6XTG+3BsiRoFR31Co0ahUaPgqE9okdTIc4UkEhEFlmnTpumVV17RW2+9pZycnKDbXnDBBXI6ndq1a5cuuOACZWVl6eDBg022O3z4sDIzM/3uw+VyyeVyNbnf6XS22jdSaz72WKFGwVGf0KhRaNQoOOoTmpUaNaeWlkYJGYahqVOnqri4WH//+9/Vu3fvkM/ZsWOH3G63evToIUnKz89XVVWV3nnnHe82mzdvVlVVlQYPHmzx8AEAQHtgqYXljjvu0IoVK/Tyyy8rOTnZ2+ckNTVViYmJ+uSTT7R8+XJdfvnlSk9P186dO3XXXXfp/PPP14UXXihJOvfcc3XZZZdpypQp3uHOt956q8aOHcsIIQAA4JelFpYlS5aoqqpKw4YNU48ePbw/q1atkiR16tRJb7zxhkaNGqWzzz5b06dPV0FBgdasWaOEhATvfpYvX66+ffuqoKBABQUF6tevn5577rnonhkAAGgzLLWwGIYR9PHc3FytW7cu5H7S0tK0bNkyKy8NAADaMdYSAgAAtkdgAQAAtkdgAQAAtkdgAQAAtkdgAQAAtkdgAQAAtkdgAQAAtkdgAQAAtkdgAQAAtkdgAQAAtkdgAQAAtkdgAQAAtkdgAQAAtkdgAQAAtkdgAQAAtkdgAQAAtkdgAQAAtkdgAQAAtkdgAQAAtkdgAQAAtkdgAQAAtkdgAQAAtkdgAQAAtkdgAQAAtkdgAQAAtkdgAQAAtkdgAQAAtkdgAQAAtkdgAQAAtkdgAQAAtkdgAQAAtkdgAQAAtkdgAQAAtkdgAQAAtkdgAQAAtmcpsCxYsEA/+MEPlJycrIyMDF111VX66KOPfLapra3VtGnTlJ6eri5duuiKK67Qvn37fLbZs2ePxo0bpy5duig9PV3Tp09XXV1d888GAAC0SZYCy7p163THHXdo06ZNKisr09dff62CggKdOHHCu82MGTP04osvauXKlVq/fr2OHz+usWPHqr6+XpJUX1+vMWPG6MSJE1q/fr1Wrlyp1atX66677orumQEAgDajo5WNS0pKfG4//fTTysjI0JYtW3TxxRerqqpKS5cu1XPPPadLL71UkrRs2TLl5uZqzZo1GjVqlEpLS7Vz507t3btX2dnZkqRHHnlEN910k+bPn6+UlJQonRoAAGgrLAWWxqqqqiRJaWlpkqQtW7bI7XaroKDAu012drby8vK0YcMGjRo1Shs3blReXp43rEjSqFGjVFtbqy1btmj48OFNXqe2tla1tbXe29XV1ZIkt9stt9vdnFOIOc/xtrbjjiVqFBz1CY0ahUaNgqM+oUVSo+bUM+LAYhiGZs6cqYsuukh5eXmSpMrKSnXq1Eldu3b12TYzM1OVlZXebTIzM30e79q1qzp16uTdprEFCxZo3rx5Te4vLS1VUlJSpKcQV2VlZfE+BNujRsFRn9CoUWjUKDjqE5qVGtXU1ET8OhEHlqlTp+qDDz7Q+vXrQ25rGIYcDof3dsN/B9qmoTlz5mjmzJne29XV1crNzVVBQUGru4TkdrtVVlamkSNHyul0xvtwbIkaBUd9QqNGoVGj4KhPaJHUyHOFJBIRBZZp06bplVde0VtvvaWcnBzv/VlZWaqrq9ORI0d8WlkOHTqkwYMHe7fZvHmzz/6OHDkit9vdpOXFw+VyyeVyNbnf6XS22jdSaz72WKFGwVGf0KhRaNQoOOoTmpUaNaeWlkYJGYahqVOnqri4WH//+9/Vu3dvn8f79+8vp9Pp0zxUUVGh7du3ewNLfn6+tm/froqKCu82paWlcrlc6t+/f8QnAgAA2i5LLSx33HGHVqxYoZdfflnJycnePiepqalKTExUamqqbrnlFt11113q1q2b0tLSNGvWLPXt29c7aqigoEDnnXeeCgsL9dBDD+nLL7/UrFmzNGXKlFZ3eQcAAMSGpcCyZMkSSdKwYcN87n/66ad10003SZIeffRRdezYUdddd51OnjypESNG6JlnnlFCQoIkKSEhQa+99ppuv/12XXjhhUpMTNSkSZP08MMPN/9sAABAm2QpsBiGEXKbzp076/HHH9fjjz8ecJszzzxTf/nLX6y8NAAAaMdYSwgAANgegQUAANgegQUAANgegQUAANgegQUAANgegQUAANgegQUAANgegQUAANgegQUAANgegQUAANgegQUAANgegQUAANgegQUAANgegQUAANgegQUAANgegQUAANgegQUAANgegQUAANgegQUAANgegQUAANgegQUAANgegQUAANgegQUAANgegQUAANgegQUAANgegQUAANgegQUAANgegQUAANgegQUAANgegQUAANgegQUAANgegQUAANgegQUAANgegQUAANgegQUAANie5cDy1ltv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nDhR55xzjpxOp84//3zNmDFDEydOlESNGopWLfz93nlut6V6SdJXX32le+65R5MmTfIudhjLGjHfcIw5HA6f24ZhNLmvrZs6dao++OADrV+/PuS2jevjr1ZtoYZ79+7VnXfeqdLSUnXu3Dns57WX+kjSqVOnNGDAAD3wwAOSpPPPP187duzQkiVL9KMf/ci7XajfsbZco1WrVmnZsmVasWKFvvvd76q8vFwzZsxQdna2Jk+e7N2uPdeosWjUwt8+Aj23tXK73ZowYYJOnTqlJ5980uexWNWIFpYYSU9PV0JCQpM0eejQoSbJsy2bNm2aXnnlFb355pvKycnx3p+VlaW6ujodOXLEZ/uG9cnKympSvyNHjsjtdrf6Gm7ZskWHDh1S//791bFjR3Xs2FHr1q3Tr3/9a3Xs2FGZmZntuj6S1KNHD5133nk+95177rnas2ePJPP8aSGgGAAAA7pJREFUpabf2BrX6ODBg032ffjw4TZRo5/+9Ke65557NGHCBPXt21eFhYX6yU9+4m21o0anRasW/n7vDh06JKlp601r5Xa7dd1112n37t0qKyvztq5Isa0RgSVGOnXqpP79+6usrMzn/rKyMg0ePDhORxU7hmFo6tSpKi4u1t///nf17t3b5/H+/fvL6XT61KeiokLbt2/31ic/P1/bt29XRUWFd5vS0lK5XC71798/NifSQkaMGKFt27apvLzc+zNgwADdcMMN3n+35/pI0oUXXthkKPy//vUv9erVS5LUu3dvZWVl+dSorq5O69at86lRVVWV3nnnHe82mzdvVlVVVZv4PaypqVGHDr5/1hMSErzDmqnRadGqRX5+vt566y2f6QNKS0uVnZ2ts846KzYn04I8YWXXrl1as2aNunXr5vN4TGsUdvdcNJtnWPPSpUuNnTt3GjNmzDC6dOlifPrpp/E+tBb3P//zP0Zqaqqxdu1ao6KiwvtTU1Pj3ea2224zcnJyjDVr1hhbt241LrnkEr/DdkeMGGFs3brVWLNmjZGTk9Nmhu021nCUkGFQn3feecfo2LGjMX/+fGPXrl3G8uXLjaSkJGPZsmXebRYuXGikpqYaxcXFxrZt24yJEyf6Habar18/Y+PGjcbGjRuNvn37tsohu/5MnjzZ6Nmzp3dYc3FxsZGenm7Mnj3bu017qtGxY8eM999/33j//fcNScaiRYuM999/3zvCJRq1OHr0qJGZmWlMnDjR2LZtm1FcXGykpKS0mmHNwWrkdruNK664wsjJyTHKy8t9/nbX1tZ69xGrGhFYYux///d/jV69ehmdOnUyLrjgAu+w3rZOkt+fp59+2rvNyZMnjalTpxppaWlGYmKiMXbsWGPPnj0++/nss8+MMWPGGImJiUZaWpoxdepUn6FybUnjwEJ9DOPVV1818vLyDJfLZZxzzjnG7373O5/HT506ZcydO9fIysoyXC6XcfHFFxvbtm3z2eaLL74wbrjhBiM5OdlITk42brjhBuPIkSOxPI0WU11dbdx5553GmWeeaXTu3Nn45je/adx3330+Hy7tqUZvvvmm3787kydPNgwjerX44IMPjCFDhhgul8vIysoyioqKWs2Q5mA12r17d8C/3W+++aZ3H7GqkcMwWsl0fAAAoN2iDwsAALA9AgsAALA9AgsAALA9AgsAALA9AgsAALA9AgsAALA9AgsAALA9AgsAALA9AgsAALA9AgsAALA9AgsAALA9AgsAALC9/w9+ZQJ4NaaBRAAAAABJRU5ErkJggg==\n",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "%matplotlib inline\n",
    "\n",
    "# Plot outputs\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "# Cleans up the appearance\n",
    "plt.rcdefaults()\n",
    "\n",
    "plt.scatter(\n",
    "  y_test,\n",
    "  predicted,\n",
    "  color='blue',\n",
    "  linewidth=1\n",
    ")\n",
    "plt.grid(True)\n",
    "\n",
    "plt.xticks()\n",
    "plt.yticks()\n",
    "\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "anaconda-cloud": {},
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.8"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}
